/**
 *    Copyright (C) 2008,2009  Victor Smirnov <aist11@gmail.com>
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License along
 *    with this program; if not, write to the Free Software Foundation, Inc.,
 *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 *    See LICENSE.exceptions in the root folder of this project for possible
 *    exceptions
 *
 */

#ifndef _CUBEFS_CORE_BTREE_PAGES_NODE_BASE_HPP
#define	_CUBEFS_CORE_BTREE_PAGES_NODE_BASE_HPP

#include <cubefs/core/btree/locators.hpp>

#include <cubefs/core/tools/reflection.hpp>
#include <cubefs/core/container/container.hpp>

#include <cubefs/api/models/logs.hpp>

namespace cubefs    {
namespace btree     {

using namespace cubefs::ctr;
using namespace cubefs::tools;


#pragma pack(1)

template <typename PageMgr_>
class TreePage: public PageMgr_::Page {
    
    typedef BitBuffer<32>                   TreeFlagsType;

    TreeFlagsType                           tree_flags_;
    typename PageMgr_::Page::ID             parent_id_;
    Int                                     parent_idx_;

public:

    enum {
        LEAF          = 0,
        ROOT          = 1,
        BITMAP        = 2
    }                                       FLAGS;

    typedef PageMgr_                        PageMgr;

    typedef TreePage<PageMgr>               Me;
    typedef typename PageMgr::Page          Base;
    typedef typename Base::ID               ID;

    TreePage(): Base() {}

    // for access from getters
    const TreeFlagsType& tree_flags() const {
        return tree_flags_;
    }

    TreeFlagsType& tree_flags() {
        return tree_flags_;
    }


    const ID& parent_id() const {
        return parent_id_;
    }

    ID& parent_id() {
        return parent_id_;
    }

    const Int &parent_idx() const {
        return parent_idx_;
    }

    Int &parent_idx() {
        return parent_idx_;
    }


    inline bool is_root() const {
        return tree_flags().is_bit(ROOT);
    }

    void set_root(bool root) {
        return tree_flags().set_bit(ROOT, root);
    }

    inline bool is_leaf() const {
        return tree_flags().is_bit(LEAF);
    }

    void set_leaf(bool leaf) {
        return tree_flags().set_bit(LEAF, leaf);
    }

    inline bool is_bitmap() const {
        return tree_flags().is_bit(BITMAP);
    }

    void set_bitmap(bool bitmap) {
        return tree_flags().set_bit(BITMAP, bitmap);
    }


    void BuildFieldsList(MetadataList &list, Long &abi_ptr) const {
        Base::BuildFieldsList(list, abi_ptr);

        FieldFactory<BitField<TreeFlagsType> >::create(list, tree_flags(), "LEAF",   LEAF,   abi_ptr);
        FieldFactory<BitField<TreeFlagsType> >::create(list, tree_flags(), "ROOT",   ROOT,   abi_ptr);
        FieldFactory<BitField<TreeFlagsType> >::create(list, tree_flags(), "BITMAP", BITMAP, abi_ptr);

        abi_ptr += ValueTraits<TreeFlagsType>::Size;

        FieldFactory<ID>::create(list,  parent_id(),  "PARENT_ID",  abi_ptr);
        FieldFactory<Int>::create(list, parent_idx(), "PARENT_IDX", abi_ptr);
    }

    template <typename PageType>
    void CopyFrom(PageType* page)
    {
        Base::CopyFrom(page);

        this->tree_flags()  = page->tree_flags();
        this->parent_id()   = page->parent_id();
        this->parent_idx()  = page->parent_idx();
    }
};

template <typename CountType>
class BTreeCountersBase {
    CountType page_count_;
    CountType key_count_;

public:
    BTreeCountersBase(): page_count_(0), key_count_(0) {}

    BTreeCountersBase(CountType pc, CountType kc): page_count_(pc), key_count_(kc) {}

    const CountType &page_count() const
    {
        return page_count_;
    }

    CountType &page_count()
    {
        return page_count_;
    }

    const CountType &key_count() const
    {
        return key_count_;
    }

    CountType &key_count()
    {
        return key_count_;
    }

    BTreeCountersBase operator-() const {
        return BTreeCountersBase(-page_count(), -key_count());
    }

    BTreeCountersBase operator-(const BTreeCountersBase &other) const {
        return BTreeCountersBase(page_count() - other.page_count(), key_count() - other.key_count());
    }

    void operator-=(const BTreeCountersBase &other) {
        page_count() -= other.page_count();
        key_count() -= other.key_count();
    }

    BTreeCountersBase operator+(const BTreeCountersBase &other) const {
        return BTreeCountersBase(page_count() + other.page_count(), key_count() + other.key_count());
    }

    void operator+=(const BTreeCountersBase &other) {
        page_count() += other.page_count();
        key_count() += other.key_count();
    }

    bool operator==(const BTreeCountersBase &other) {
        return  page_count() == other.page_count() &&
                key_count() == other.key_count();
    }

    bool operator!=(const BTreeCountersBase &other) {
        return !operator==(other);
    }

    MetadataList GetFields(Long &abi_ptr) const {
        MetadataList list;
        FieldFactory<CountType>::create(list, page_count(), "PAGE_COUNT", abi_ptr);
        FieldFactory<CountType>::create(list, key_count(), "KEY_COUNT", abi_ptr);
        return list;
    }
};

template <typename T>
cubefs::api::Logger& operator<<(cubefs::api::Logger &log, const BTreeCountersBase<T>& value) {
    log.log("Counters[");
    log.log("page_count=");
    log.log(value.page_count());
    log.log("; key_count=");
    log.log(value.key_count());
    log.log("]");
    return log;
}


template <
		typename Profile_,
        typename CountersType,
        typename BaseType
>
class NodePageBase: public BaseType
{
    Short           level_;
    CountersType    counters_;

public:
    typedef Profile_															Profile;
    typedef BaseType                                                            Base;
    typedef CountersType                                                        Counters;

    NodePageBase(): Base(), level_(0), counters_()
    {
        init();
    }

    void init() {
    	Base::init();
    	counters().page_count() = 1;
    }

    const Counters &counters() const
    {
        return counters_;
    }

    Counters &counters()
    {
        return counters_;
    }

    const Short &level() const
    {
        return level_;
    }

    Short &level()
    {
        return level_;
    }

    void BuildFieldsList(MetadataList &list, Long &abi_ptr) const {
        Base::BuildFieldsList(list, abi_ptr);

        FieldFactory<Short>::create(list, level(), "LEVEL", abi_ptr);
        FieldFactory<Counters>::create(list, counters(), "COUNTERS", abi_ptr);
    }

    template <typename PageType>
    void CopyFrom(PageType* page)
    {
        Base::CopyFrom(page);

        this->level()       = page->level();
        this->counters()    = page->counters();
    }
};

#pragma pack()

}


namespace ctr {

using namespace cubefs::btree;

template <typename Profile, typename Name, typename Default>
class TypeFactory<RootProfile, Profile, BTreeCountersFactory<Name>, Default>    {
public:
    typedef BTreeCountersBase<BigInt>                                           Type;
};

template <typename Profile, typename Name, typename BasePagesPartsList, typename Default>
class TypeFactory<RootProfile, Profile, NodeBaseFactory<Name, BasePagesPartsList>, Default> {
    
    typedef typename CountersLocator<Profile, Name>::Type                       BTreeCountersType;
    typedef typename ContainerTypesLocator<Profile>::PageManagerType            PageMgr;

public:

    typedef PageBuilder<Profile, BasePagesPartsList, TreePage<PageMgr> >        PartsType;

    typedef NodePageBase<Profile, BTreeCountersType,  PartsType>                         Type;
};


}
}





#endif // _CUBEFS_CORE_BTREE_PAGES_NODE_BASE_HPP
